//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Collections;
using System.Collections.Specialized;
using System.Workflow.ComponentModel.Design;
using System.ComponentModel.Design;
using System.Workflow.ComponentModel.Compiler;
using Microsoft.Research.ScientificWorkflow;

namespace Microsoft.Research.ScientificWorkflow.Activities
{
    [Name("Container Activity for running the while loop", "While")]
    [Description("While activity for running a set of activities until a condition is true.")]
    [WorkflowCategory("Control Flow")]
    [HideActivity(true)]
    public class WhileActivity : System.Workflow.Activities.SequenceActivity, 
        IActivityEventListener<ActivityExecutionStatusChangedEventArgs>
	{
		public WhileActivity()
		{
		}

        public static System.Workflow.ComponentModel.DependencyProperty ConditionProperty =
            System.Workflow.ComponentModel.DependencyProperty.Register("Condition", typeof(bool),
            typeof(WhileActivity));

        [RequiredInputParam]
        [Name("Condtion")]
        [Description("Boolean value to determine continue running or stopping the while loop.")]
        public bool Condition
        {
            get { return (bool)GetValue(WhileActivity.ConditionProperty); }
            set { SetValue(WhileActivity.ConditionProperty, value); }
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            ExecuteIteration(executionContext);
            return ActivityExecutionStatus.Executing;
        }

        private void ExecuteIteration(ActivityExecutionContext parentCtx)
        {
            System.Workflow.ComponentModel.Activity act = this.Activities[0];

            ActivityExecutionContext newContext = parentCtx.ExecutionContextManager.CreateExecutionContext(act);
            newContext.Activity.RegisterForStatusChange(
                System.Workflow.ComponentModel.Activity.ClosedEvent, this);

            newContext.ExecuteActivity(newContext.Activity);
        }

        public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
        {
            //get the AEC for the ForEach activity
            ActivityExecutionContext ctx = sender as ActivityExecutionContext;
            if (ctx == null)
                throw new ArgumentNullException("sender", "The sender must be an AEC");

            //unregister for the events and close the context
            e.Activity.UnregisterForStatusChange(
                System.Workflow.ComponentModel.Activity.ClosedEvent, this);

            //get the child context and mark it as complete
            ActivityExecutionContext childContext = ctx.ExecutionContextManager.GetExecutionContext(e.Activity);
            ctx.ExecutionContextManager.CompleteExecutionContext(childContext);

            //determine if we should close or execute another iteration
            if (this.Condition == true)
            {
                ExecuteIteration(ctx);
            }
            else
            {
                ctx.CloseActivity();
            }
        }

	}
}
